package com.anxin.act.process.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.anxin.act.busFlow.service.WfBusNodeService;
import com.anxin.act.process.dao.ActProcessDao;
import com.anxin.act.process.dto.CcProcessDTO;
import com.anxin.act.process.vo.*;
import com.anxin.act.task.dao.*;
import com.anxin.act.task.entity.*;
import com.anxin.act.task.service.*;
import com.anxin.act.task.vo.FormPropertyVo;
import com.anxin.act.task.vo.HiTaskVo;
import com.anxin.act.task.vo.TaskVo;
import com.anxin.act.utils.ActProcessUtils;
import com.anxin.act.utils.ActTaskUtils;
import com.anxin.act.utils.ActUtils;
import com.anxin.common.constant.HttpStatus;
import com.anxin.common.exception.BaseException;
import com.anxin.common.utils.DateUtils;
import com.anxin.common.utils.IdGen;
import com.anxin.common.utils.LogUtils;
import com.anxin.common.utils.StringUtils;
import com.anxin.common.utils.spring.SpringUtils;
import com.anxin.common.utils.sys.RoleUtils;
import com.anxin.common.utils.sys.UserUtils;
import com.anxin.framework.redis.RedisCache;
import com.anxin.framework.security.service.SysLoginService;
import com.anxin.framework.web.entity.AjaxResult;
import com.anxin.framework.web.page.PageDomain;
import com.anxin.framework.web.page.TableDataInfo;
import com.anxin.framework.web.page.TableSupport;
import com.anxin.osbProinstInfor.entity.OsbProinstInfor;
import com.anxin.osbProinstInfor.service.OsbProinstInforService;
import com.anxin.sys.file.dao.FileBaseDao;
import com.anxin.sys.file.service.FileBaseService;
import com.anxin.sys.message.utils.SendMessageUtils;
import com.anxin.sys.system.dao.SysUserDao;
import com.anxin.sys.system.entity.SysRole;
import com.anxin.sys.system.entity.SysUser;
import com.anxin.sys.system.utils.ConfigUtils;
//import io.swagger.annotations.ApiOperation;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.*;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.el.JuelExpression;
import org.activiti.engine.impl.juel.Node;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.VariableInstanceEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.delegate.ActivityBehavior;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.runtime.InterpretableExecution;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.impl.variable.StringType;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.io.IOUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 流程管理
 * @author: liuxiangyu
 * @date: 2020/3/9 15:20
 */
@Service
public class ActProcessService {
    private static Logger logger = LoggerFactory.getLogger("sys-error");
    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ActProcessDao actProcessDao;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ActFreeFlowService actFreeFlowService;

    @Autowired
    private JumpTaskService jumpTaskService;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private ProcessStartService processStartService;

    @Autowired
    private WfBusNodeService wfBusNodeService;

    @Autowired
    private ActSendTaskService actSendTaskService;

    @Autowired
    private ActTaskService actTaskService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ActSelfBuiltService actSelfBuiltService;

    @Autowired
    private ViewHiTaskDao viewHiTaskDao;

    @Autowired
    private WfCcRecordService wfCcRecordService;

    @Autowired
    private WfActHiCommentService wfActHiCommentService;

    @Autowired
    private ActDockingService actDockingService;

    @Autowired
    private WfActRuTaskDao wfActRuTaskDao;

    @Autowired
    private FileBaseService fileBaseService;

    @Autowired
    private FileBaseDao fileBaseDao;

    @Autowired
    private ActProcessService actProcessService;

    @Autowired
    private WfTaskReadService wfTaskReadService;

    @Autowired
    private ViewRuTaskDao viewRuTaskDao;

    @Autowired
    private WfActHiTaskDao wfActHiTaskDao;

    @Autowired
    private TaskService taskService;

    @Autowired
    private ActTaskDao actTaskDao;

    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private SysLoginService sysLoginService;
    @Autowired
    private FlowInterfacesService flowInterfacesService;
    @Autowired
    private OsbProinstInforService osbProinstInforService;

    /**
     * 查询流程列表
     * @param processVo
     * @return
     */
    public TableDataInfo findList(ProcessVo processVo){
        PageDomain pageDomain = TableSupport.buildPageRequest();

        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().latestVersion().orderByProcessDefinitionCategory().asc();

        //流程名称
        if (StringUtils.isNotBlank(processVo.getName())){
            processDefinitionQuery.processDefinitionNameLike("%"+processVo.getName()+"%");
        }

        //流程标识
        if (StringUtils.isNotBlank(processVo.getKey())){
            processDefinitionQuery.processDefinitionKeyLike("%"+processVo.getKey()+"%");
        }

        //流程分类
        if (StringUtils.isNotBlank(processVo.getCategory())){
            processDefinitionQuery.processDefinitionCategory(processVo.getCategory());
        }


        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        List<ProcessDefinition> processDefinitions = processDefinitionQuery.listPage(pageDomain.getFirstResult(), pageDomain.getMaxResults());
        rspData.setRows(this.getProcessVoList(processDefinitions));
        rspData.setTotal(processDefinitionQuery.count());
        return rspData;

    }

    /**
     * 查询流程列表，不带分页，用户选择流程的下拉框
     * @return
     */
    public List<ProcessVo> listData(){
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().latestVersion().orderByProcessDefinitionCategory().asc();
        return this.getProcessVoList(processDefinitionQuery.list());
    }

    /**
     * 查询审批记录
     * @param actId 流程实例ID
     * @param sid 流程中节点的ID
     * @return
     */
    public AjaxResult<List<HiTaskVo>> approvalRecord(String actId, String sid){
        List<HiTaskVo> resTaskList = new ArrayList<>();

        List<ViewHiTask> hiTaskList = viewHiTaskDao.findList(new ViewHiTask(actId,sid));

        // 流程实例
        HistoricProcessInstance historicProcessInstance = ActProcessUtils.getHiProcessInstance(actId);

        // 查询流程抄送信息
        Map<String, StringBuffer> ccByActId = wfCcRecordService.findCcByActId(actId);


        // 启动信息
        HiTaskVo startTaskVo = new HiTaskVo();
        this.setSpecialComment(startTaskVo,historicProcessInstance,"start");
        resTaskList.add(startTaskVo);


        Map<String, String> wfTaskReadMap = wfTaskReadService.findByActId(actId);

        for (ViewHiTask viewHiTask : hiTaskList) {
            HiTaskVo hiTaskVo = new HiTaskVo(viewHiTask,wfTaskReadMap);
            // 抄送用户
            hiTaskVo.setCcUser(ccByActId.get(viewHiTask.getId()) != null ? ccByActId.get(viewHiTask.getId()).toString() : "");

            List<WfActHiComment> commentList = wfActHiCommentService.getCommentList(viewHiTask);
            hiTaskVo.setCommentList(commentList);

            // 查询附件信息
            hiTaskVo.setTaskAttachments(fileBaseService.findList(viewHiTask.getId(),"act_approval"));
            //判断当前审批的用户是否已经已读了
//            this.updateUserReadStatus(viewHiTask, hiTaskVo);
            resTaskList.add(hiTaskVo);
        }

        // 终止信息
        HiTaskVo stopInfo = new HiTaskVo();
        actProcessService.setSpecialComment(stopInfo,historicProcessInstance,"stop");
        if (StringUtils.isNotBlank(stopInfo.getSubmitType())){
            resTaskList.add(stopInfo);
        }

        // 重要信息脱敏
        List<String> userList = new ArrayList<> ();
        for (HiTaskVo hiTaskVo : resTaskList) {
            if (hiTaskVo.getApproverUserList () != null && hiTaskVo.getApproverUserList ().size () > 0) {
                for (SysUser sysUser : hiTaskVo.getApproverUserList ()) {
                    if (sysUser != null) {
                        userList.add (sysUser.getUserName ());
                        sysUser.setPhonenumber (sysLoginService.ecrypt (sysUser.getPhonenumber ()));
                        sysUser.setEmail (sysLoginService.ecrypt (sysUser.getEmail ()));
                        sysUser.setUserName (sysLoginService.ecrypt (sysUser.getUserName ()));
                        sysUser.setNickName (sysLoginService.ecrypt (sysUser.getNickName ()));
                        sysUser.setUserKey (sysLoginService.ecrypt (sysUser.getUserKey ()));
                        sysUser.setStaffCode (sysLoginService.ecrypt (sysUser.getStaffCode ()));
                        sysUser.setDeputyAccountNumber (sysLoginService.ecrypt (sysUser.getDeputyAccountNumber ()));
                    }
                }
            }
        }
        // 判断是否越权
//        if (! userList.contains (UserUtils.getUserName ())) {
//            throw new BaseException ("数据越权，无法查看");
//        }
        return AjaxResult.success(resTaskList);
    }

    /**
     * 判断当前审批的用户是否已经已读了
     * @param viewHiTask
     * @param hiTaskVo
     */
    private void updateUserReadStatus(ViewHiTask viewHiTask, HiTaskVo hiTaskVo) {
        if (viewHiTask.getStartTime()!=null && viewHiTask.getEndTime()==null) {
            //当前未审批的人员。查询是否已读  ，因为存在会签的情况，所以需要用map存储
            HashMap<String, Boolean> readStatusMap = new HashMap<>();
            List<String> assigneeList = ActUtils.getAssigneeByTask(viewHiTask.getTaskId());
            for (String userName : assigneeList) {
                SysUser user = UserUtils.getUserByUserName(userName);
                if (user != null) {
                    readStatusMap.put(userName, actTaskService.getReadStatus(viewHiTask.getTaskId(), user.getId()));
                }
            }
            hiTaskVo.setReadStatusMap(readStatusMap);
        }
    }


    /**
     * 查询我的申请
     * @param processVo
     * @return
     */
    public TableDataInfo<ProcessVo> processList(ProcessVo processVo){
        //准备当结果返回的list
        List<ProcessVo> resList = new ArrayList<>();

        //分页属性
        PageDomain pageDomain = TableSupport.buildPageRequest();

        HistoricProcessInstanceQuery processQuery = historyService.createHistoricProcessInstanceQuery().orderByProcessInstanceStartTime().desc();

        // 申请人
        if (StringUtils.isNotBlank(processVo.getApplyUserId()) || StringUtils.isNotBlank(processVo.getApplyUserName())){
            String userName = processVo.getApplyUserName();
            if (StringUtils.isBlank(userName)){
                userName = UserUtils.getUser(processVo.getApplyUserId()).getUserName();
            }
            processQuery.startedBy(userName);
        }


        // 按流程审批状态查询 D:待审批  Z:审批终止  W:审批完成
        if ("D".equals(processVo.getActStatus())){
            processQuery.unfinished();
        }else if ("Z".equals(processVo.getActStatus())){
            processQuery.deleted();
        }else if ("W".equals(processVo.getActStatus())){
            processQuery.finished().notDeleted();
        }
        // 按流程查询
        if (StringUtils.isNotBlank(processVo.getKey())){
            processQuery.processDefinitionKey(processVo.getKey());
        }


        // 按待办标题查询
        if (StringUtils.isNotBlank(processVo.getTitle())) {
            processQuery.variableValueLike("title", "%"+processVo.getTitle()+"%");
        }

        // 流程启动时间的开始时间
        if (StringUtils.isNotBlank(processVo.getBeginTime())){
            processQuery.startedAfter(DateUtils.getBeginTime(processVo.getBeginTime()));
        }

        // 流程启动时间的结束时间
        if (StringUtils.isNotBlank(processVo.getBeginTime())){
            processQuery.startedBefore(DateUtils.getEndTime(processVo.getEndTime()));
        }


        List<HistoricProcessInstance> applyList = processQuery.listPage(pageDomain.getFirstResult(), pageDomain.getMaxResults());

        for (HistoricProcessInstance historicProcessInstance : applyList) {
            resList.add(new ProcessVo(historicProcessInstance));
        }

        //组件分页数据
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setRows(resList);
        rspData.setTotal(processQuery.count());

        return rspData;

    }


    /**
     * 将 ProcessDefinition list 转为 process list
     * @param processDefinitions
     * @return
     */
    private List<ProcessVo> getProcessVoList(List<ProcessDefinition> processDefinitions){
        List<ProcessVo> processVos = new ArrayList<>();
        for (ProcessDefinition processDefinition : processDefinitions) {
            if ("123".equals(processDefinition.getName()) || "储备流程".equals(processDefinition.getName()) || "预投流程".equals(processDefinition.getName()) ||"测试流程".equals(processDefinition.getName())){
                continue;
            }
            ProcessVo processVo = new ProcessVo();
            processVo.setId(processDefinition.getId());
            processVo.setCategory(processDefinition.getCategory());
            processVo.setKey(processDefinition.getKey());
            processVo.setDeploymentId(processDefinition.getDeploymentId());
            processVo.setName(processDefinition.getName());
            processVo.setVersion(processDefinition.getVersion());
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(processDefinition.getDeploymentId()).singleResult();
            processVo.setDeployTime(deployment.getDeploymentTime());

            processVos.add(processVo);

        }
        return processVos;
    }




    /**
     * 初始化流程启动时需要的流程变量
     * @return
     */
    public Map<String,Object> initProcessVar(RuProcessVo ruProcessVo){

        SysUser applyUser = null;

        // 设置申请人
        if (StringUtils.isNotBlank(ruProcessVo.getApplyUserId())){
            applyUser = UserUtils.getUser(ruProcessVo.getApplyUserId());
        }

        if (applyUser == null){
            applyUser = UserUtils.getUser();
        }

        // 存入流程变量
        Map<String,Object> processVar = new HashMap<>();
        // 待办标题
        processVar.put("title",ruProcessVo.getTitle());
        // 申请人登录名
        processVar.put("applyUserName",applyUser.getUserName());
        // 申请人ID
        processVar.put("applyUserId",applyUser.getId());
        // 申请人展示名
        processVar.put("applyNickName",applyUser.getNickName());
        // 流程启动时间
        processVar.put("applyTime",System.currentTimeMillis());
        // 流程表单组件地址
        processVar.put("actFormPath",ruProcessVo.getFormPath());
        // 流程表单组件Id
        processVar.put("actFormId",ruProcessVo.getFormId());
        // 流程表单只读和打印地址
        processVar.put("actViewPath",ruProcessVo.getViewPath());
        // 业务表名
        processVar.put("actDataTable",ruProcessVo.getDataTable());
        // 业务id
        processVar.put("actDataId",ruProcessVo.getDataId());
        // 是否加急
        processVar.put("urgent",ruProcessVo.getIsUrgent());
        // 表单类型
        if (StringUtils.isNotBlank(ruProcessVo.getFormType())){
            processVar.put("actFormType",ruProcessVo.getFormType());
        }
        // 部门负责人
        if(ruProcessVo.getNextApply() != null){
            processVar.put("nextApply",ruProcessVo.getNextApply().toJSONString());
        }

        // 相关个人账号
        if (ruProcessVo.getBusinessPathArray() != null){
            processVar.put("businessPathArray",ruProcessVo.getBusinessPathArray().toJSONString());
        }

        // 设置申请人选择的审批人
        if (ruProcessVo.getApplyChoiceAssignee() != null){
            List<ApplyChoiceVo> applyChoiceAssignee = ruProcessVo.getApplyChoiceAssignee();
            for (ApplyChoiceVo applyChoiceVo : applyChoiceAssignee) {
                processVar.put("applyChoice_"+applyChoiceVo.getTaskKey(),applyChoiceVo.getUserList().toJSONString());
            }
        }

        // 关联流程
        JSONArray associatedProcessArray = new JSONArray();
        JSONArray associatedProcess = ruProcessVo.getAssociatedProcess();
        for (int i = 0; i < associatedProcess.size(); i++) {
            JSONObject jsonObject = associatedProcess.getJSONObject(i);
            JSONObject associatedProcessJson = new JSONObject();
            associatedProcessJson.put("id",jsonObject.getString("id"));
            associatedProcessJson.put("title",jsonObject.getString("title"));
            associatedProcessArray.add(associatedProcessJson);
        }
        // 是否加急
        processVar.put("associatedProcess",associatedProcessArray.toJSONString());

        return processVar;
    }




    /**
     * 启动流程
     * @param ruProcessVo
     * @return
     */
    public ProcessInstance startProcess(RuProcessVo ruProcessVo){
        //当前用户
        SysUser user = UserUtils.getUser();

        //初始化流程启动时需要的流程变量
        Map processVar = this.initProcessVar(ruProcessVo);



        // 启动流程
        String businessKey = ruProcessVo.getDataTable()+":"+ruProcessVo.getDataId();
        identityService.setAuthenticatedUserId(user.getUserName());
        ProcessInstance procIns = runtimeService.startProcessInstanceByKey(ruProcessVo.getProcessKey(), businessKey, processVar);

        // 设置流程标题
        runtimeService.setProcessInstanceName(procIns.getProcessInstanceId(),ruProcessVo.getTitle());

        // 自由流审批人配置
        if("act_free_flow_approval".equals(ruProcessVo.getProcessKey())){
            actFreeFlowService.startApproval(procIns.getId(),ruProcessVo.getNextApply());
        }

        // 自建流程审批
        if("act_self_built_process".equals(ruProcessVo.getProcessKey())){
            actSelfBuiltService.startApproval(procIns.getId(),ruProcessVo.getNextApply());
        }

        //启动流程后修改业务表的 流程实例ID（act_id） 流程审批状态(act_status) 俩个字段
        actProcessDao.updateDataTable(ruProcessVo.getDataTable(),ruProcessVo.getDataId(),"D",procIns.getId());

        // 启动流程后AA跳
        jumpTaskService.jumpTask(procIns.getId(),null);

        // 已对接流程标识
        String actFlow = ConfigUtils.get("act_flow");
        if (actFlow.contains(ruProcessVo.getProcessKey())){
            //获取审批人
            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().processInstanceId(procIns.getProcessInstanceId()).activityType("userTask")
                    .orderByHistoricActivityInstanceStartTime().asc().list();

            List<String> strings = new ArrayList<>();
            List<SysUser> sysUsers = new ArrayList<>();
            String processDefinitionId = ActProcessUtils.getProcessDefinitionId(procIns.getProcessInstanceId());
            ProcessInstance processInstance = ActProcessUtils.getProcessInstance(procIns.getProcessInstanceId());
            ActivityImpl activityImpl = ActUtils.getActivityImpl(processDefinitionId, processInstance.getActivityId());
            // 节点名称
            Class<? extends ActivityBehavior> aClass = activityImpl.getActivityBehavior().getClass();
            try{
                if (aClass == UserTaskActivityBehavior.class) {
                    UserTaskActivityBehavior activityBehavior = (UserTaskActivityBehavior) activityImpl.getActivityBehavior();
                    sysUsers = actProcessService.setUserTaskActivityBehavior(activityBehavior.getTaskDefinition(), procIns.getProcessInstanceId());
                } else if (aClass == ParallelMultiInstanceBehavior.class) {
                    ParallelMultiInstanceBehavior activityBehavior = (ParallelMultiInstanceBehavior) activityImpl.getActivityBehavior();
                    sysUsers = actProcessService.setExpression(activityBehavior.getCollectionExpression(), procIns.getProcessInstanceId());
                } else if (aClass == SequentialMultiInstanceBehavior.class) {
                    SequentialMultiInstanceBehavior activityBehavior = (SequentialMultiInstanceBehavior) activityImpl.getActivityBehavior();
                    sysUsers = actProcessService.setExpression(activityBehavior.getCollectionExpression(), procIns.getProcessInstanceId());
                }
            } catch (Exception e){
                e.printStackTrace();
            }
            if(sysUsers !=null && sysUsers.size()>0){
                for (SysUser sysUser : sysUsers) {
                    strings.add(sysUser.getUserName());
                }
            } else{
                for (HistoricActivityInstance historicActivityInstance : list) {
                    if(historicActivityInstance.getEndTime() == null && !StringUtils.equals(historicActivityInstance.getAssignee(),"-1")){
                        strings.add(historicActivityInstance.getAssignee());
                    }
                }
            }

            //接口启动流程
            boolean  flowFlag = flowInterfacesService.startProcess(ruProcessVo, procIns,StringUtils.isNotEmpty(strings)?  strings.toString().replaceAll("\\[","").replaceAll("]",""): "liuzhikun");

            //如果接口调用失败则不启动当前的流程
            if(!flowFlag){
                throw new BaseException("启动流程接口启动失败，请联系管理员进行查看！");
            }
        }

        // 保存项目进展
        if ("wf_bus_node".equals(ruProcessVo.getDataTable())){
            wfBusNodeService.sendEvent(ruProcessVo.getDataId(),ruProcessVo.getTitle());
        }

        // 流程启动后执行
        processStartService.startEnd(ruProcessVo.getDataTable(),ruProcessVo.getDataId(),procIns.getId());

        // reids 缓存流程变量
        redisCache.setCacheObject("process_var_" + procIns.getProcessDefinitionId(), processVar, 1, TimeUnit.MINUTES);

        // 发送待办提醒
        actSendTaskService.sendTask(procIns.getId(),"todoTask");

        return procIns;
    }

    /**
     * 终止流程
     * @param actId
     * @param reason
     * @return
     */
    public AjaxResult stopProcess(String actId,String reason){
        ProcessInstance processInstance = ActProcessUtils.getProcessInstance(actId);
        if (processInstance == null){
            return AjaxResult.error("流程已经结束,无法再次终止");
        }
        String act_flow = ConfigUtils.get("act_flow");
        if (act_flow.contains(processInstance.getProcessDefinitionKey())){
            //接口终止流程
            boolean flowFlag = flowInterfacesService.stopProcess(actId);
            if(!flowFlag){
                return AjaxResult.error("终止流程接口启动失败，请联系管理员进行查看！");
            }
        }

        //修改业务表状态
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(actId).includeProcessVariables().singleResult();
        String dataTable = historicProcessInstance.getProcessVariables().get("actDataTable").toString();
        String dataId = historicProcessInstance.getProcessVariables().get("actDataId").toString();
        actProcessDao.updateDataTable(dataTable,dataId,"Z",null);

        // 修改项目进展状态
        if ("wf_bus_node".equals(dataTable)){
            // 修改项目进展状态等
            wfBusNodeService.sendEvent(dataId,historicProcessInstance.getName());
        }

        // 终止流程的用户
        runtimeService.setVariable(actId,"actDeleteUser",UserUtils.getUser().getUserName());
        processEngine.getRuntimeService().deleteProcessInstance(actId, reason);

        // 终止加签任务
        wfActRuTaskDao.deleteByActId(actId);

        // 对接待办删除
        actDockingService.delTaskByActId(actId);



        return AjaxResult.success();
    }

    /**
     * 查询流程XML
     * @param procDefId
     * @return
     */
    public AjaxResult getXml(String procDefId){
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).singleResult();
        InputStream resourceAsStream = null;
        byte[] b = new byte[1024];
        int len = -1;

        StringBuffer xml = new StringBuffer();
        try {
            resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
            while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
                xml.append(new String(b,0, len));
            }
        }catch (Exception e){
            logger.error("查询流程XML异常", e);
        }finally {
            try {
                if (resourceAsStream != null) {
                    resourceAsStream.close();
                }
            } catch (IOException ioException) {
                System.out.println(ioException);
            }
        }
        return AjaxResult.success(xml);
    }


    /**
     * 生成流程图
     *
     * @param actId 任务ID
     */
    //@ApiOperation("生成流程图")
    public String genProcessDiagram(String actId) {
        HistoricProcessInstance hiProcessInstance = ActProcessUtils.getHiProcessInstance(actId);
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(hiProcessInstance.getProcessDefinitionId());
        //将xml文件转换成BpmnModel
        //创建转换对象
        BpmnXMLConverter converter = new BpmnXMLConverter();
        byte[] bytes = converter.convertToXML(bpmnModel, "utf-8");
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        SAXReader saxReader = new SAXReader();
        //2、使用解析器对象读取XML文档生成Document对象
        Document document = null;
        try {
            document = saxReader.read(in);
        } catch (DocumentException e) {
            e.printStackTrace();
        }

        // 历史线走过的节点（节点边线、连接线）
        List<String> hiSequenceFlowSidList = new ArrayList<>();
        // 历史走过的节点（需要背景填充ID）
        List<String> hiNodeFlowSidList = new ArrayList<>();
        // 当前的节点sid（需要背景填充ID）
        List<String> currentNodeFlowSidList = new ArrayList<>();
        // 当前任务
        List<Task> ruTaskList = taskService.createTaskQuery().processInstanceId(actId).list();
        for (Task task : ruTaskList) {
            // 当前节点sid（背景填充）
            currentNodeFlowSidList.add(task.getTaskDefinitionKey());
        }
        // 历史走过的节点这些节点不包含走过的线，所以走过的线单独处理
        List<HistoricActivityInstance> hiTaskList = historyService.createHistoricActivityInstanceQuery().processInstanceId(actId).orderByHistoricActivityInstanceStartTime().asc().list();
        for (int i = 0; i < hiTaskList.size(); i++) {
            // 历史节点的线sid（包含当前节点）
            String activityId = hiTaskList.get(i).getActivityId();
            hiNodeFlowSidList.add(activityId);
//            if (!currentNodeFlowSidList.contains(activityId)) {
//                // 判断是否是当前节点，若是不则进行记录
//                List<PvmTransition> outgoingTransitions = ActUtils.getActivity(hiProcessInstance.getProcessDefinitionId(), hiTaskList.get(i).getActivityId()).getOutgoingTransitions();
//                for (PvmTransition outgoingTransition : outgoingTransitions) {
//                    String sid = outgoingTransition.getId();
//                    hiSequenceFlowSidList.add(sid);
//                }
//            }

        }
        for (int i = 0; i < hiTaskList.size() - 1; i++) {
            HistoricActivityInstance sourceActivity = hiTaskList.get(i);
            HistoricActivityInstance targetActivity = hiTaskList.get(i + 1);

            String sourceActivityId = sourceActivity.getActivityId();
            String targetActivityId = targetActivity.getActivityId();

            FlowNode sourceNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sourceActivityId);
            List<SequenceFlow> outgoingFlows = sourceNode.getOutgoingFlows();

            for (SequenceFlow sequenceFlow : outgoingFlows) {
                if (sequenceFlow.getTargetRef().equals(targetActivityId)) {
                    hiSequenceFlowSidList.add(sequenceFlow.getId());
                    break;
                }
            }
        }
        editXmlElement(document, hiSequenceFlowSidList, hiNodeFlowSidList, currentNodeFlowSidList);

        return document.asXML().replaceAll("[$]", "");
    }

    /**
     * 生成流程图表单按钮组件
     *
     * @param processDefinitionKey
     */
    //@ApiOperation("生成流程图")
    public String genProcessFormDiagram(String processDefinitionKey) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .latestVersion().processDefinitionKey(processDefinitionKey).singleResult();
        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinition.getId());
        //将xml文件转换成BpmnModel
        //创建转换对象
        BpmnXMLConverter converter = new BpmnXMLConverter();
        byte[] bytes = converter.convertToXML(bpmnModel, "utf-8");
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        SAXReader saxReader = new SAXReader();
        //2、使用解析器对象读取XML文档生成Document对象
        Document document = null;
        try {
            document = saxReader.read(in);
            Element rootElement = document.getRootElement();
            // 要给process节点替换的字符串
            String uuid = "replaceStr";
            // 由于网管节点中的X不渲染，这里需要在网管对应的样式标签中添加 isMarkerVisible="true" 属性。这里先获取网管的ID值集合
            List<String> gatewayIdList = new ArrayList<>();
            // 获取XML文件的根节点下的所有的process子节点（这里只有一个）
            List<Element> processElementList = rootElement.elements("process");
            for (Element processElement : processElementList) {
                // 由于bpmn.js渲染的时候，节点process中的属性id,name中不能存在中文，所以这里进行替换成英文
                Attribute id = processElement.attribute("id");
                id.setValue(uuid);
                Attribute name = processElement.attribute("name");
                name.setValue(uuid);
                // 获取process节点下的所有的网管节点,并循环记录到网管节点的ID集合中
                List<Element> gatewayList = processElement.elements("exclusiveGateway");
                for (Element gateway : gatewayList) {
                    Attribute gatewayElement = gateway.attribute("id");
                    gatewayIdList.add(gatewayElement.getValue());
                }
            }
            List<Element> BPMNDiagramElementList = rootElement.elements("BPMNDiagram");
            for (Element BPMNDiagramElement : BPMNDiagramElementList) {
                // 替换上面循环取出process节点布局中的中id和bpmnElement的属性的值
                Attribute BPMNDiagramId = BPMNDiagramElement.attribute("id");
                BPMNDiagramId.setValue("BPMNDiagram_" + uuid);
                // 获取BPMNPlane
                List<Element> BPMNPlaneElements = BPMNDiagramElement.elements("BPMNPlane");
                for (Element bpmndiElement : BPMNPlaneElements) {
                    Attribute bpmnElement = bpmndiElement.attribute("bpmnElement");
                    bpmnElement.setValue(uuid);
                    Attribute bpmnElementId = bpmndiElement.attribute("id");
                    bpmnElementId.setValue("BPMNPlane_" + uuid);
                    // 获取BPMNShapeList
                    List<Element> BPMNPlaneChildElements = bpmndiElement.elements();
                    for (Element bpmnplaneChildElement : BPMNPlaneChildElements) {
                        Attribute bpmn = bpmnplaneChildElement.attribute("bpmnElement");
                        if (gatewayIdList.contains(bpmn.getValue())) {
                            bpmnplaneChildElement.addAttribute("isMarkerVisible","true");
                        }
                    }
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return document.asXML().replaceAll("[$]", "");
    }

    /**
     * 编辑流程图中的xml元素
     * @param document 当前xml的dom
     * @param hiSequenceFlowSidList 历史线走过的节点sid集合（节点边线、连接线）
     * @param hiNodeFlowSidList 历史走过的节点sid集合（需要背景填充ID）
     * @param currentNodeFlowSidList 当前的节点sid集合（需要背景填充ID）
     */
    public void editXmlElement(Document document, List<String> hiSequenceFlowSidList, List<String> hiNodeFlowSidList, List<String> currentNodeFlowSidList) {
        // 当前节点填充的颜色
        String currentNodeColor = ConfigUtils.get("current_node_color");
        // 当前节点边框颜色
        String currentNodeLineColor = ConfigUtils.get("current_node_line_color");
        // 历史节点填充颜色
        String hiNodeColor = ConfigUtils.get("hi_node_color");
        // 历史节点线的颜色
        String hiLineColor = ConfigUtils.get("hi_line_color");
        // process节点的ID值
        String IdStr = "";
        // 要给process节点替换的字符串
        String uuid = "replaceStr";
        Element rootElement = document.getRootElement();
        // 由于网管节点中的X不渲染，这里需要在网管对应的样式标签中添加 isMarkerVisible="true" 属性。这里先获取网管的ID值集合
        List<String> gatewayIdList = new ArrayList<>();
        // 获取XML文件的根节点下的所有的process子节点（这里只有一个）
        List<Element> processElementList = rootElement.elements("process");
        for (Element processElement : processElementList) {
            // 由于bpmn.js渲染的时候，节点process中的属性id,name中不能存在中文，所以这里进行替换成英文
            Attribute id = processElement.attribute("id");
            IdStr = id.getValue();
            id.setValue(uuid);
            Attribute name = processElement.attribute("name");
            name.setValue(uuid);
            // 获取process节点下的所有的网管节点,并循环记录到网管节点的ID集合中
            List<Element> gatewayList = processElement.elements("exclusiveGateway");
            for (Element gateway : gatewayList) {
                Attribute gatewayElement = gateway.attribute("id");
                gatewayIdList.add(gatewayElement.getValue());
            }
            List<Element> userTaskElements = processElement.elements("userTask");
            for (Element userTaskElement : userTaskElements) {
                Attribute attribute = userTaskElement.attribute("id");
                // hiNodeFlowSidList 历史走过的节点sid集合（需要背景填充ID） hiNodeColor 历史节点填充颜色
                if (hiNodeFlowSidList.contains(attribute.getValue())) {
                    userTaskElement.addAttribute("history","history");
                }
                // currentNodeFlowSidList 当前的节点sid集合（需要背景填充ID） currentNodeColor 当前节点填充的颜色
                if (currentNodeFlowSidList.contains(attribute.getValue())) {
                    userTaskElement.addAttribute("history","history");
                }
            }
        }
        List<Element> BPMNDiagramElementList = rootElement.elements("BPMNDiagram");
        for (Element BPMNDiagramElement : BPMNDiagramElementList) {
            // 替换上面循环取出process节点布局中的中id和bpmnElement的属性的值
            Attribute BPMNDiagramId = BPMNDiagramElement.attribute("id");
            BPMNDiagramId.setValue("BPMNDiagram_" + uuid);
            // 获取BPMNPlane
            List<Element> BPMNPlaneElements = BPMNDiagramElement.elements("BPMNPlane");
            for (Element bpmndiElement : BPMNPlaneElements) {
                Attribute bpmnElement = bpmndiElement.attribute("bpmnElement");
                bpmnElement.setValue(uuid);
                Attribute bpmnElementId = bpmndiElement.attribute("id");
                bpmnElementId.setValue("BPMNPlane_" + uuid);
                // 获取BPMNShapeList
                List<Element> BPMNPlaneChildElements = bpmndiElement.elements();
                for (Element bpmnplaneChildElement : BPMNPlaneChildElements) {
                    Attribute bpmn = bpmnplaneChildElement.attribute("bpmnElement");
                    if (gatewayIdList.contains(bpmn.getValue())) {
                        bpmnplaneChildElement.addAttribute("isMarkerVisible","true");
                    }
                    // hiSequenceFlowSidList 历史线走过的节点sid集合（节点边线、连接线） hiLineColor 历史节点线的颜色
                    if (hiSequenceFlowSidList.contains(bpmn.getValue())) {
                        bpmnplaneChildElement.addAttribute("bioc:stroke",hiLineColor);
                    }
                    // hiNodeFlowSidList 历史走过的节点sid集合（需要背景填充ID） hiNodeColor 历史节点填充颜色
                    if (hiNodeFlowSidList.contains(bpmn.getValue())) {
                        bpmnplaneChildElement.addAttribute("bioc:fill",hiNodeColor);
                    }
                    // currentNodeFlowSidList 当前的节点sid集合（需要背景填充ID） currentNodeColor 当前节点填充的颜色
                    if (currentNodeFlowSidList.contains(bpmn.getValue())) {
                        bpmnplaneChildElement.addAttribute("bioc:fill",currentNodeColor);
                        bpmnplaneChildElement.addAttribute("bioc:stroke",currentNodeLineColor);
                    }
                }
            }
        }
    }
    /**
     * 查询流程详情
     * @param processId
     * @return
     */
    public AjaxResult<RuProcessVo> getProcessInfo(String processId){
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).includeProcessVariables().singleResult();
        if(historicProcessInstance == null){
            OsbProinstInfor byProInst = osbProinstInforService.getByProInst(processId);
            if(byProInst != null){
                historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(byProInst.getProcessinstId()).includeProcessVariables().singleResult();
            }
        }
        // 判断是否越权
        TaskVo taskVo = new TaskVo();
        List<ViewHiTask> viewHiTasks = actTaskService.hiList(taskVo);
        Map<String, List<ViewHiTask>> collect = viewHiTasks.stream().collect(Collectors.groupingBy(ViewHiTask::getActId));
        Set<String> strings = collect.keySet();
        if(!strings.contains(processId) && !StringUtils.equals(historicProcessInstance.getStartUserId(),UserUtils.getUserName()) && !StringUtils.equals("系统管理员", UserUtils.getNickName())){
            throw new BaseException("数据越权，无法查看");
        }
        // 设置临时权限，供用户查看待办表单
        redisCache.setCacheObject("act_permissions_"+UserUtils.getUser().getId(), "act",5, TimeUnit.SECONDS);
        return AjaxResult.success(new RuProcessVo(historicProcessInstance));
    }

    /**
     * 查询表名字和ID查询业务数据
     * @param dataTable
     * @param dataId
     * @return
     */
    public Map<String,Object> selectData(String dataTable,String dataId){
        return actProcessDao.selectData(dataTable,dataId);
    }

    /**
     * 获取流程图
     * @param actId
     * @return
     */
    public AjaxResult getProcessPhoto(String actId){
        ProcessPhotoVo processPhotoVo = new ProcessPhotoVo();

        String processDefinitionKey = ActProcessUtils.getProcessDefinitionKey(actId);
        processPhotoVo.setProcessDefinitionKey(processDefinitionKey);

        // 自建流程
        if ("act_self_built_process".equals(processDefinitionKey)){
            JSONArray userNickNameArray = new JSONArray();

            JSONArray assigneesArray = JSONArray.parseArray(ActUtils.getProcessVar(actId).get("selfBuiltAssigneesAll").toString());
            for (int i = 0; i < assigneesArray.size(); i++) {
                JSONArray userNameArray = assigneesArray.getJSONArray(i);
                userNickNameArray.add(UserUtils.getNickNamesByUserNameArray(userNameArray));
            }
            processPhotoVo.setAssigneesArray(userNickNameArray);

        }else{
            processPhotoVo.setPhotoBase64(this.getPhoto(actId));
        }

        return AjaxResult.success(processPhotoVo);
    }


    /**
     * 获取流程图
     * @param actId
     * @return
     */
    public String getPhoto(String actId){
        InputStream is = null;
        String imgBase64 = null;
        if (StringUtils.isNotBlank(actId)){
            try {
                is = this.tracePhoto(actId);

                byte[] bytes = IOUtils.toByteArray(is);

                imgBase64 = Base64.getEncoder().encodeToString(bytes);
            }catch (Exception e){
                logger.error("获取流程图片异常",e);
            }finally {
                if (is != null){
                    try {
                        is.close();
                    } catch (IOException e) {
                        LogUtils.error("获取流程图异常",e);
                    }
                }
            }
        }
        return "data:image/png;base64," + imgBase64;
    }

    /**
     * 读取带跟踪的图片
     * @param actId
     * @return
     */
    public InputStream tracePhoto(String actId) {

        // 根据流程定义ID获得流程实例
        String processDefinitionId = ActProcessUtils.getProcessDefinitionId(actId);

        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinitionId);

        // 得到正在执行的环节
        List<String> activeIds = new ArrayList<String>();
        List<Task> taskList = ActTaskUtils.getCurrentTaskList(actId);
        for (Task task : taskList) {
            String[] taskKey = task.getTaskDefinitionKey().split(":");
            if (taskKey.length<3) {
                activeIds.add(taskKey[0]);
            }else {
                activeIds.add(taskKey[1]);
            }

        }

        DefaultProcessDiagramGenerator dpg = new DefaultProcessDiagramGenerator();
        // 获得流程图的流对象，这里显示的加载了字体
        InputStream is = dpg.generateDiagram(bpmnModel, "png", activeIds, Collections.<String> emptyList(), "FangSong",
                "FangSong", "utf-8", null, 1.0);
        return is;
    }

    /**
     * 设置流程结束,调整，启动等特护comment
     * @param hiTaskVo
     * @param historicProcessInstance
     * @param type
     */
    public void setSpecialComment(HiTaskVo hiTaskVo, HistoricProcessInstance historicProcessInstance, String type){
        if ("start".equals(type)){ // 启动流程
            hiTaskVo.setSubmitType(type);
            if (historicProcessInstance.getProcessVariables().get("applyNickName") != null){
                hiTaskVo.setStartUser(historicProcessInstance.getProcessVariables().get("applyNickName").toString());
                hiTaskVo.setStartDate(DateUtils.format(new Date(Long.parseLong(historicProcessInstance.getProcessVariables().get("applyTime").toString()))));
            }
        }else if ("adjustNode".equals(type)){ // 终止流程
            HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskId(hiTaskVo.getTaskId()).includeTaskLocalVariables().singleResult();
            if (task.getTaskLocalVariables().get("act_adjustNode") != null){
                hiTaskVo.setSubmitType(type);
                hiTaskVo.setAdjustNodeUser(task.getTaskLocalVariables().get("act_adjustNode_user") != null ? task.getTaskLocalVariables().get("act_adjustNode_user").toString() : null);
                hiTaskVo.setAdjustNode(task.getTaskLocalVariables().get("act_adjustNode_node") != null ? task.getTaskLocalVariables().get("act_adjustNode_node").toString() : null);
            }

        }else if ("stop".equals(type)){ // 节点调整
            if (StringUtils.isNotBlank(historicProcessInstance.getDeleteReason())) {
                String actDeleteUser = historicProcessInstance.getProcessVariables().get("actDeleteUser").toString();
                if (StringUtils.isNotBlank(actDeleteUser)) {
                    SysUser stopUser = UserUtils.getUserByUserName(actDeleteUser);
                    if (stopUser != null) {
                        actDeleteUser = stopUser.getNickName();
                    }
                }
                hiTaskVo.setSubmitType(type);
                hiTaskVo.setStopUser(actDeleteUser);
                hiTaskVo.setStopDate(DateUtils.dateTime(historicProcessInstance.getEndTime()));
                hiTaskVo.setStopReason(historicProcessInstance.getDeleteReason());

            }
        }
    }

    /**
     * 删除可用流程
     * @param deploymentId
     * @return
     */
    //@ApiOperation(value="删除可用流程",notes="作者:刘翔宇")
    public AjaxResult delProcess(String deploymentId){

        long count = historyService.createHistoricProcessInstanceQuery().deploymentId(deploymentId).count();
        if (count > 0){
            return AjaxResult.error("流程已使用,无法删除");
        }
        try {
            List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().active().deploymentId(deploymentId).list();
            for (ProcessInstance p:list) {
                runtimeService.deleteProcessInstance(p.getProcessInstanceId(), "");
            }
            repositoryService.deleteDeployment(deploymentId, true);
        } catch (Exception e) {
            logger.error("流程删除失败:" + deploymentId, e);
            return AjaxResult.error();
        }
        return AjaxResult.success();
    }

    /**
     * 根据processKey 获取
     * @param processKey 流程定义的Key
     * @return
     */
    public AjaxResult<String> getApplyChoiceByKey(String processKey){
        List<ApplyChoiceVo> applyChoiceVoList = new ArrayList<>();

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey).latestVersion().singleResult();
        if (processDefinition!= null){
            ProcessDefinitionEntity pde  = (ProcessDefinitionEntity)((RepositoryServiceImpl)repositoryService).getDeployedProcessDefinition(processDefinition.getId());
            List<ActivityImpl> activities = pde.getActivities();
            for (ActivityImpl activity : activities) {
                if ("true".equals(activity.getProperty("applychoice"))){
                    ApplyChoiceVo applyChoiceVo = new ApplyChoiceVo(activity.getId(), activity.getProperty("name").toString());

                    if (activity.getProperty("applychoicescope") != null && StringUtils.isNotBlank(activity.getProperty("applychoicescope").toString())){
                        String applyChoiceScopes = activity.getProperty("applychoicescope").toString();

                        applyChoiceVo.setUserScopeList(this.getUserListByRoleScopes(applyChoiceScopes));
                    }
                    applyChoiceVoList.add(applyChoiceVo);
                    //applyChoiceVoList.
                }

            }
        }

        return AjaxResult.success(applyChoiceVoList);
    }

    /**
     * 根据配置的角色范围获取用户集合
     * @param applyChoiceScope
     * @return
     */
    public JSONArray getUserListByRoleScopes(String applyChoiceScope){
        List<String> userIdList = new ArrayList<>();
        JSONArray userArray = new JSONArray();
        String[] applyChoiceScopes = applyChoiceScope.split(",");
        for (String choiceScope : applyChoiceScopes) {
            SysRole sysRole = RoleUtils.getByKey(choiceScope);
            if (sysRole != null){
                List<String> userList = UserUtils.getUserIdByRoleKey(sysRole.getRoleKey());
                for (String userId : userList) {
                    if (!userIdList.contains(userId)){
                        SysUser user = UserUtils.getUser(userId);
                        if (user != null){
                            JSONObject userJson = new JSONObject();
                            userJson.put("id",user.getId());
                            userJson.put("nickName",user.getNickName());
                            userArray.add(userJson);
                            userIdList.add(userId);
                        }
                    }
                }
            }

        }
//        for (String choiceScope : applyChoiceScopes) {
//            SysRole sysRole = RoleUtils.getByKey(choiceScope);
//            if (sysRole != null){
//                JSONObject parentJson = new JSONObject();
//                parentJson.put("parentId","0");
//                parentJson.put("id",sysRole.getId());
//                parentJson.put("label",sysRole.getRoleName());
//                parentJson.put("disabled","true");
//
//                userArray.add(parentJson);
//
//                List<String> userList = UserUtils.getUserIdByRoleKey(sysRole.getRoleKey());
//                JSONArray userChildrenArray = new JSONArray();
//                for (String userId : userList) {
//                    SysUser user = UserUtils.getUser(userId);
//                    if (user != null && "0".equals(user.getStatus())){
//                        JSONObject userJson = new JSONObject();
//                        userJson.put("parentId",sysRole.getId());
//                        userJson.put("id",user.getId());
//                        userJson.put("label",user.getNickName());
//                        userChildrenArray.add(userJson);
//                    }
//                }
//                parentJson.put("children",userChildrenArray);
//
//            }
//
//        }



        return userArray;
    }

    /**
     * 根据流程定义ID获取流程图
     * @param processDefinitionKey 流程实例ID
     * @return
     */
    public AjaxResult showFlowChart(String processDefinitionKey){
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .latestVersion().processDefinitionKey(processDefinitionKey).singleResult();

        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinition.getId());

        DefaultProcessDiagramGenerator dpg = new DefaultProcessDiagramGenerator();
        // 获得流程图的流对象，这里显示的加载了字体
        InputStream is = null;

        String imgBase64 = null;

        try {
            is = dpg.generateDiagram(bpmnModel, "png", new ArrayList<>(),
                    Collections.<String>emptyList(), "FangSong",
                    "FangSong", "utf-8", Thread.currentThread().getContextClassLoader(), 1.0);
            byte[] bytes = IOUtils.toByteArray(is);
            imgBase64 = Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
            LogUtils.error(e.getMessage(),e);
        }

        return AjaxResult.setSuccessData("data:image/png;base64," + imgBase64);
    }


    /**
     * 根据流程定义ID获取流程图
     * @param processDefinitionKey 流程实例ID
     * @return
     */
    public AjaxResult showFlowAssignees(String processDefinitionKey) throws Exception {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().latestVersion().processDefinitionKey(processDefinitionKey).singleResult();

        ProcessDefinitionEntity pde  = (ProcessDefinitionEntity)((RepositoryServiceImpl)repositoryService).getDeployedProcessDefinition(processDefinition.getId());

        Map<String, TaskDefinition> taskDefinitionMap = pde.getTaskDefinitions();
        Set<String> keySet = taskDefinitionMap.keySet();

        // 审批人集合
        List<FlowAssigneesVo> flowAssigneesVoList = new ArrayList<>();

        for (String key : keySet) {
            // 每个节点的信息，名称和审批人集合
            FlowAssigneesVo flowAssigneesVo = new FlowAssigneesVo();

            TaskDefinition taskDefinition = taskDefinitionMap.get(key);
            flowAssigneesVo.setTaskName(taskDefinition.getNameExpression().getExpressionText());

            Set<Expression> candidateUserIdExpressions = taskDefinition.getCandidateUserIdExpressions();
            for (Expression candidateUserIdExpression : candidateUserIdExpressions) {
                ExecutionEntity executionEntity = this.getExecutionEntity(null);
                String className = ((JuelExpression) candidateUserIdExpression).getClassName();

                String methodName = ((JuelExpression) candidateUserIdExpression).getMethods().trim();

                Node parameter = ((JuelExpression) candidateUserIdExpression).getParameter();

                Object bean = SpringUtils.getBean(className);

                Class<?> mClass = bean.getClass();

                try {
                    Class[] classesType = new Class[parameter.getCardinality()];
                    Object[] classesValue = new Object[parameter.getCardinality()];

                    for (int i = 0; i < parameter.getCardinality(); i++) {

                        if ("execution".equals(parameter.getChild(i).toString())){
                            classesValue[i] = executionEntity;
                            classesType[i] = DelegateExecution.class;
                        }else {
                            classesValue[i] = parameter.getChild(i).toString().replace("\"","");
                            classesType[i] = String.class;
                        }

                    }
                    Method method =  mClass.getMethod(methodName,classesType);
                    Object invoke = method.invoke(bean,classesValue);
                    flowAssigneesVo.setUserList(UserUtils.getUserListByUserNames(invoke.toString()));


                } catch (NoSuchMethodException e) {
                    LogUtils.error(e.getMessage(),e);
                }
            }
            flowAssigneesVoList.add(flowAssigneesVo);
        }

        return AjaxResult.success(flowAssigneesVoList);
    }

    /**
     * 根据流程实例ID和节点aid获取没有审批过的节点数据
     * @param actId 流程实例ID
     * @param sid 流程实例ID
     * @return
     */
    public AjaxResult showNodeAssignees(String actId, String sid) throws Exception {
        List<HiTaskVo> resTaskList = new ArrayList<>();
        // 流程实例
        HistoricProcessInstance historicProcessInstance = ActProcessUtils.getHiProcessInstance(actId);
        // 启动信息
        HiTaskVo startTaskVo = new HiTaskVo();
        this.setSpecialComment(startTaskVo,historicProcessInstance,"start");
        resTaskList.add(startTaskVo);

        String processDefinitionId = ActProcessUtils.getProcessDefinitionId(actId);
        ActivityImpl activityImpl = ActUtils.getActivityImpl(processDefinitionId, sid);
        Class<? extends ActivityBehavior> aClass = activityImpl.getActivityBehavior().getClass();
        // 节点名称
        String taskName = (String) activityImpl.getProperties().get("name");
        if (aClass == UserTaskActivityBehavior.class) {
            UserTaskActivityBehavior activityBehavior = (UserTaskActivityBehavior) activityImpl.getActivityBehavior();
            setSingleTaskList(resTaskList, taskName, setUserTaskActivityBehavior(activityBehavior.getTaskDefinition(), actId));
        } else if (aClass == ParallelMultiInstanceBehavior.class) {
            ParallelMultiInstanceBehavior activityBehavior = (ParallelMultiInstanceBehavior) activityImpl.getActivityBehavior();
            getMultiLineList(resTaskList, taskName, setExpression(activityBehavior.getCollectionExpression(), actId));
        } else if (aClass == SequentialMultiInstanceBehavior.class) {
            SequentialMultiInstanceBehavior activityBehavior = (SequentialMultiInstanceBehavior) activityImpl.getActivityBehavior();
            getMultiLineList(resTaskList, taskName, setExpression(activityBehavior.getCollectionExpression(), actId));
        }
        return AjaxResult.success(resTaskList);
    }

    /**
     * 根据流程实例KEY和节点aid获取没有审批过的节点数据
     * @param processKey 流程实例ID
     * @param sid 流程实例ID
     * @return
     */
    public AjaxResult showNodeFormAssignees(String processKey, String sid) throws Exception {
        List<HiTaskVo> resTaskList = new ArrayList<>();
        String  processDefinitionId = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey).latestVersion().singleResult().getId();
        // 每个节点的信息，名称和审批人集合
        ActivityImpl activityImpl = ActUtils.getActivityImpl(processDefinitionId, sid);
        Class<? extends ActivityBehavior> aClass = activityImpl.getActivityBehavior().getClass();
        // 节点名称
        String taskName = (String) activityImpl.getProperties().get("name");
        if (aClass == UserTaskActivityBehavior.class) {
            UserTaskActivityBehavior activityBehavior = (UserTaskActivityBehavior) activityImpl.getActivityBehavior();
            setSingleTaskList(resTaskList, taskName, setUserTaskActivityBehavior(activityBehavior.getTaskDefinition(), null));
        } else if (aClass == ParallelMultiInstanceBehavior.class) {
            ParallelMultiInstanceBehavior activityBehavior = (ParallelMultiInstanceBehavior) activityImpl.getActivityBehavior();
            getMultiLineList(resTaskList, taskName, setExpression(activityBehavior.getCollectionExpression(), null));
        } else if (aClass == SequentialMultiInstanceBehavior.class) {
            SequentialMultiInstanceBehavior activityBehavior = (SequentialMultiInstanceBehavior) activityImpl.getActivityBehavior();
            getMultiLineList(resTaskList, taskName, setExpression(activityBehavior.getCollectionExpression(), null));
        }
        return AjaxResult.success(resTaskList);
    }

    /**
     * 根据节点封装单行的数据
     * @param resTaskList
     * @param taskName
     * @param userList
     */
    public void setSingleTaskList(List<HiTaskVo> resTaskList, String taskName, List<SysUser> userList) {
        HiTaskVo hiTaskVo = new HiTaskVo();
        ArrayList<String> approverList = new ArrayList<>();
        if (userList != null && !userList.isEmpty()) {
            for (SysUser user : userList) {
                approverList.add(user.getNickName());
            }
        }
        hiTaskVo.setTaskName(taskName);
        hiTaskVo.setApprover(approverList);
        resTaskList.add(hiTaskVo);
    }

    /**
     * 获取多行用户实例数据
     * @param resTaskList 审批信息集合
     * @param taskName 任务名称
     * @param userList 用户集合
     */
    public void getMultiLineList(List<HiTaskVo> resTaskList, String taskName, List<SysUser> userList) {
        if (userList != null && !userList.isEmpty()) {
            for (SysUser user : userList) {
                HiTaskVo taskVo = new HiTaskVo();
                ArrayList<String> approverList = new ArrayList<>();
                taskVo.setTaskName(taskName);
                approverList.add(user.getNickName());
                taskVo.setApprover(approverList);
                resTaskList.add(taskVo);
            }
        }
    }

    /**
     * 获取审批人
     * @param expression
     * @param actId 流程实例ID
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public List<SysUser> setExpression(Expression expression, String actId) throws IllegalAccessException, InvocationTargetException {
        List<SysUser> userList = new ArrayList<>();
        ExecutionEntity executionEntity = null;
        if (StringUtils.isNotEmpty(actId)) {
            executionEntity = this.getExecutionEntity(actId);
        } else {
            executionEntity = this.getExecutionEntity();
        }
        String className = ((JuelExpression) expression).getClassName();
        String methodName = ((JuelExpression) expression).getMethods().trim();
        Node parameter = ((JuelExpression) expression).getParameter();
        Object bean = SpringUtils.getBean(className);
        Class<?> mClass = bean.getClass();
        try {
            Class[] classesType = new Class[parameter.getCardinality()];
            Object[] classesValue = new Object[parameter.getCardinality()];
            for (int i = 0; i < parameter.getCardinality(); i++) {
                if ("execution".equals(parameter.getChild(i).toString())) {
                    classesValue[i] = executionEntity;
                    classesType[i] = DelegateExecution.class;
                } else {
                    classesValue[i] = parameter.getChild(i).toString().replace("\"", "");
                    classesType[i] = String.class;
                }
            }
            Method method = mClass.getMethod(methodName, classesType);
            Object invoke = method.invoke(bean, classesValue);
            String userNameString = invoke.toString();
            if (StringUtils.isNotEmpty(userNameString)) {
                userNameString = userNameString.replace("[", "").replace("]","");
                userList = UserUtils.getUserListByUserNames(userNameString);
            }
        } catch (NoSuchMethodException e) {
            LogUtils.error(e.getMessage(), e);
        }
        return userList;
    }

    /**
     * 普通类型
     * @param taskDefinition
     * @param actId 流程实例ID
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public List<SysUser> setUserTaskActivityBehavior(TaskDefinition taskDefinition, String actId) throws IllegalAccessException, InvocationTargetException {
        List<SysUser> userList = new ArrayList<>();
        Set<Expression> candidateUserIdExpressions = taskDefinition.getCandidateUserIdExpressions();
        for (Expression candidateUserIdExpression : candidateUserIdExpressions) {
            ExecutionEntity executionEntity = null;
            if (StringUtils.isNotEmpty(actId)) {
                executionEntity = this.getExecutionEntity(actId);
            } else {
                executionEntity = this.getExecutionEntity();
            }
            String className = ((JuelExpression) candidateUserIdExpression).getClassName();
            String methodName = ((JuelExpression) candidateUserIdExpression).getMethods().trim();
            Node parameter = ((JuelExpression) candidateUserIdExpression).getParameter();
            Object bean = SpringUtils.getBean(className);
            Class<?> mClass = bean.getClass();
            try {
                Class[] classesType = new Class[parameter.getCardinality()];
                Object[] classesValue = new Object[parameter.getCardinality()];
                for (int i = 0; i < parameter.getCardinality(); i++) {
                    if ("execution".equals(parameter.getChild(i).toString())) {
                        classesValue[i] = executionEntity;
                        classesType[i] = DelegateExecution.class;
                    } else {
                        classesValue[i] = parameter.getChild(i).toString().replace("\"", "");
                        classesType[i] = String.class;
                    }
                }
                Method method = mClass.getMethod(methodName, classesType);
                Object invoke = method.invoke(bean, classesValue);
                userList = UserUtils.getUserListByUserNames(invoke.toString());
            } catch (NoSuchMethodException e) {
                LogUtils.error(e.getMessage(), e);
            }
        }
        return userList;
    }

    /**
     * 自定义 ExecutionEntity 对象
     * @return
     */
    public ExecutionEntity getExecutionEntity(String actId){
        ExecutionEntity executionEntity = new ExecutionEntity();
        ProcessInstance processInstance = ActProcessUtils.getProcessInstance(actId);
        // 运行中的待办
        if (processInstance != null) {
            executionEntity.setProcessInstance((InterpretableExecution) processInstance);
        } else {
            // 待办流程已经结束
            HistoricProcessInstance hiProcessInstance = ActProcessUtils.getHiProcessInstance(actId);
            executionEntity.setId(hiProcessInstance.getId());
        }
        return executionEntity;
    }
    /**
     * 自定义 ExecutionEntity 对象
     * @return
     */
    public ExecutionEntity getExecutionEntity(){
        ExecutionEntity executionEntity = new ExecutionEntity();
        ExecutionEntity processInstance = new ExecutionEntity();

        SysUser user = UserUtils.getUser();

        List<VariableInstanceEntity> queryVariables = new ArrayList<>();

        VariableInstanceEntity applyUserName = VariableInstanceEntity.create("applyUserName",new StringType(1000),user.getUserName());
        applyUserName.setId(IdGen.uuid());
        queryVariables.add(applyUserName);

        VariableInstanceEntity applyUserId = VariableInstanceEntity.create("applyUserId",new StringType(1000),user.getId());
        applyUserId.setId(IdGen.uuid());
        queryVariables.add(applyUserId);

        VariableInstanceEntity actDataTable = VariableInstanceEntity.create("actDataTable",new StringType(1000),user.getId());
        actDataTable.setId(IdGen.uuid());
        queryVariables.add(actDataTable);

        VariableInstanceEntity actDataId = VariableInstanceEntity.create("actDataId",new StringType(1000),user.getId());
        actDataId.setId(IdGen.uuid());
        queryVariables.add(actDataId);

        processInstance.setQueryVariables(queryVariables);
        executionEntity.setProcessInstance((InterpretableExecution) processInstance);
        return executionEntity;
    }
    /**
     * 修改业务数据的del_flag
     * @param dataTable 业务数据表
     * @param dataId 业务数据ID
     */
    public void updateDataDelFlag(String dataTable, String dataId){
        actProcessDao.updateDataDelFlag(dataTable,dataId);
    }

    /**
     * 修改业务表的 流程实例ID（act_id） 流程审批状态(act_status) 俩个字段
     *
     * @param dataTable
     * @param actStatus
     * @param actId
     */
    public void updateDataTable(String dataTable,String dataId,String actStatus,String actId){
        actProcessDao.updateDataTable(dataTable,dataId,actStatus,actId);
    }

    /**
     * 流程传阅
     */
    public AjaxResult ccProcess( CcProcessDTO ccProcessDTO){
        JSONObject messageJson = new JSONObject();
        // 待办标题
        messageJson.put("title",ActProcessUtils.getProcessTitle(ccProcessDTO.getActId()));
        // 组件地址
        messageJson.put("component","@/views/act/process/processInfoForm");
        // 数据ID
        messageJson.put("dataId",ccProcessDTO.getActId());
        // 发送消息
        SendMessageUtils.sendMessage("ccProcess", ccProcessDTO.getCcUser().toJavaList(String.class),messageJson);

        return AjaxResult.success();
    }

    /**
     * 获取流程
     * @param actId 流程实例ID
     * @return
     */
    public AjaxResult restore(String actId){
        HistoricProcessInstance hiProcessInstance = ActProcessUtils.getHiProcessInstance(actId);

        Map<String, Object> processVariables = hiProcessInstance.getProcessVariables();

        // 启动流程
        identityService.setAuthenticatedUserId(hiProcessInstance.getStartUserId());
        ProcessInstance newProcIns = runtimeService.startProcessInstanceByKey(hiProcessInstance.getProcessDefinitionKey(), hiProcessInstance.getBusinessKey(), hiProcessInstance.getProcessVariables());
        // 设置流程标题
        runtimeService.setProcessInstanceName(newProcIns.getProcessInstanceId(),hiProcessInstance.getName());
        // 修改流程启动时间
//        actTaskDao.updateProcinstStartTime(newProcIns.getId(),hiProcessInstance.getStartTime());

        // 恢复流程
        Map<String, String> idMapping = this.restoreProcess(actId, newProcIns.getProcessInstanceId());

        // 修改附件关联关系
        this.updateFile(idMapping);

        //启动流程后修改业务表的 流程实例ID（act_id） 流程审批状态(act_status) 俩个字段
        actProcessDao.updateDataTable(processVariables.get("actDataTable").toString(),processVariables.get("actDataId").toString(),"D",newProcIns.getId());


        // 获取历史任务 - 包含Activity的任务和加签的任务
//        Map<String, List<Object>> restoreHiTask = this.getRestoreHiTask(actId);

        // 新老任务的ID的映射
//        Map<String,Object> idMapping = new HashMap<>();

        // 需要过滤的任务
//        List<String> filtrationTask = new ArrayList<>();

//        this.restoreTask(newProcIns.getId(),restoreHiTask,idMapping,filtrationTask);
        // 删除之前的流程
        this.delActProcess(actId);

        return null;
    }

    /**
     * 流程恢复修改附件
     * @param idMapping 新老ID映射关系
     */
    public void updateFile(Map<String, String> idMapping){
        Set<String> keySet = idMapping.keySet();
        for (String key : keySet) {
            fileBaseDao.updateDataId(StringUtils.symbolHandler(key),StringUtils.symbolHandler(idMapping.get(key)));
        }


    }

    /**
     * 获取没有呗更新过的待办任务
     * @param taskKey
     * @param procInsId
     * @param updateRuTask
     * @return
     */
    public Task getRuTask(String taskKey, String procInsId,List<String> updateRuTask){
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(procInsId).taskDefinitionKey(taskKey).active().list();

        for (Task task : taskList) {
            if (!updateRuTask.contains(task.getId())){
                updateRuTask.add(task.getId());
                return task;
            }
        }

        if (taskList.size() > 0){
            return taskList.get(0);
        }

        return null;
    }

    /**
     * 设置审批意见字段
     * @param taskVo
     * @param commentList
     */
    public void setFormFieldList(TaskVo taskVo, List<WfActHiComment> commentList){
        List<FormPropertyVo> formFieldList = taskVo.getFormFieldList();

        Map<String,String> commentMap = new HashMap<>();

        for (WfActHiComment wfActHiComment : commentList) {
            if (StringUtils.isNotBlank(wfActHiComment.getMessage())){
                String[] message = wfActHiComment.getMessage().split(":", 2);
                if (message.length > 1){
                    commentMap.put(message[0],message[1]);
                }
            }
        }

        for (FormPropertyVo formPropertyVo : formFieldList) {
            if ("enum".equals(formPropertyVo.getType())){
                List<Map<String, String>> option = formPropertyVo.getOption();
                for (Map<String, String> map : option) {
                    if (map.get("value").equals(commentMap.get(formPropertyVo.getName()))){
                        formPropertyVo.setValue(map.get("key"));
                    }
                }

            }else {
                formPropertyVo.setValue(commentMap.get(formPropertyVo.getName()));
            }


        }

    }


    /**
     * 恢复流程
     * @param oldActId
     * @param newActId
     */
    public Map<String,String> restoreProcess(String oldActId,String newActId){
        List<ViewHiTask> hiTaskList = viewHiTaskDao.findList(new ViewHiTask(oldActId));

        // 新老任务的ID的映射 -- 老ID > 新ID
        Map<String,String> idMapping = new HashMap<>();

        // 获取已经更新过的待办任务
        List<String> updateRuTask = new ArrayList<>();

        for (ViewHiTask viewHiTask : hiTaskList) {

            if ("actTask".equals(viewHiTask.getType()) && !"comment".equals(viewHiTask.getSourceType())){

                HistoricTaskInstance historicTaskInstance = ActTaskUtils.getHiTask(viewHiTask.getId());

                Task task = this.getRuTask(historicTaskInstance.getTaskDefinitionKey(), newActId,updateRuTask);

                if (task != null){
                    idMapping.put(historicTaskInstance.getId(),task.getId());

                    taskService.setAssignee(task.getId(),historicTaskInstance.getAssignee());
                    if (historicTaskInstance.getEndTime() != null){
                        List<Comment> taskCommentList = taskService.getTaskComments(historicTaskInstance.getId());
                        for (Comment hiComment : taskCommentList) {
                            taskService.addComment(task.getId(), task.getProcessInstanceId(),hiComment.getFullMessage());
                        }
                        taskService.complete(task.getId(),historicTaskInstance.getTaskLocalVariables());
                        actTaskService.updateHiTaskTime(task.getId(),historicTaskInstance.getStartTime(),historicTaskInstance.getEndTime());
                    }else {
                        actTaskDao.updateActRuTaskTime(task.getId(), historicTaskInstance.getStartTime());
                        actTaskService.updateHiTaskTime(task.getId(),historicTaskInstance.getStartTime(),historicTaskInstance.getEndTime());
                    }
                }


            } else if ("actTask".equals(viewHiTask.getType()) && "comment".equals(viewHiTask.getSourceType())){
                // 查询历史已办
                WfActHiTask wfActHiTask = wfActHiTaskDao.getById(viewHiTask.getId());

                List<WfActHiComment> commentList = wfActHiCommentService.getCommentList(viewHiTask);
                // 加签类型
                Map<String, Object> typeAndUser = this.getAddTypeAndUser(commentList);

                // 查询对应的历史activity任务
                HistoricTaskInstance hiTask = ActTaskUtils.getHiTask(wfActHiTask.getSourceId());
                // 查询对应的新activity任务
                Task task = ActTaskUtils.getTask(hiTask.getTaskDefinitionKey(), newActId);
                taskService.setAssignee(task.getId(),viewHiTask.getAssignee());

                idMapping.put(wfActHiTask.getSourceId(),task.getId());

                TaskVo taskVo = actTaskService.getTask(task.getId());

                String completeType = typeAndUser.get("type").toString();
                taskVo.setCompleteType(completeType);
                if ("entrust".equals(completeType)){
                    taskVo.setEntrustUser(((JSONArray) typeAndUser.get("userId")).get(0).toString());
                }else {
                    taskVo.setAddUser((JSONArray) typeAndUser.get("userId"));
                }

                taskVo.setJumpEntrust(true);

                // 设置审批意见字段
                this.setFormFieldList(taskVo,commentList);

                String taskId = actTaskService.completeTask(taskVo);
                idMapping.put(wfActHiTask.getId(),taskId);
                wfActHiTaskDao.updateTime(taskId,wfActHiTask.getStartTime(),wfActHiTask.getApprovalTime());

            } else if("comment".equals(viewHiTask.getSourceType())){
                WfActHiTask oldWfActHiTask = wfActHiTaskDao.getById(viewHiTask.getId());
                WfActHiTask oldSourceWfActHiTask = wfActHiTaskDao.getById(oldWfActHiTask.getSourceId());

                String newSourceId = this.getSourceId(idMapping,oldSourceWfActHiTask.getSourceId(),newActId);
                List<WfActRuTask> ruTaskList =  new ArrayList<>();
                if(newSourceId != null){
                    ruTaskList = wfActRuTaskDao.findBySourceId(newSourceId);
                }
                if (ruTaskList.size() == 0){
                    WfActHiTask wfActHiTask= wfActHiTaskDao.getById(newSourceId);
                    if (wfActHiTask != null){
                        ruTaskList = wfActRuTaskDao.findBySourceId(wfActHiTask.getSourceId());
                    }
                }


                for (WfActRuTask wfActRuTask : ruTaskList) {
                    if (viewHiTask.getAssignee().equals(wfActRuTask.getAssignee())){
                        idMapping.put(oldWfActHiTask.getId(),wfActRuTask.getId());

                        TaskVo taskVo = actTaskService.getTask(wfActRuTask.getId());

                        List<WfActHiComment> commentList = wfActHiCommentService.getCommentList(viewHiTask);
                        Map<String, Object> typeAndUser = this.getAddTypeAndUser(commentList);
                        if (typeAndUser.get("type") != null){
                            String completeType = typeAndUser.get("type").toString();
                            taskVo.setCompleteType(completeType);
                            if ("entrust".equals(completeType)){
                                taskVo.setEntrustUser(((JSONArray) typeAndUser.get("userId")).get(0).toString());
                            }else {
                                taskVo.setAddUser((JSONArray) typeAndUser.get("userId"));
                            }
                        }else {
                            taskVo.setCompleteType("task");
                        }

                        taskVo.setJumpEntrust(true);
                        // 设置审批意见字段
                        this.setFormFieldList(taskVo,commentList);
                        String taskId = actTaskService.completeTask(taskVo);
                        wfActHiTaskDao.updateTime(taskId,oldWfActHiTask.getStartTime(),oldWfActHiTask.getApprovalTime());

                        idMapping.put(oldSourceWfActHiTask.getId(),taskId);

                    }
                }


            } else {
                // 查询历史已办
                WfActHiTask oldWfActHiTask = wfActHiTaskDao.getById(viewHiTask.getId());
                String newSourceId = this.getSourceId(idMapping,oldWfActHiTask.getSourceId(),newActId);
                List<WfActRuTask> ruTaskList = wfActRuTaskDao.findBySourceId(newSourceId);
                if (ruTaskList.size() == 0){
                    WfActHiTask wfActHiTask= wfActHiTaskDao.getById(newSourceId);
                    if (wfActHiTask != null){
                        ruTaskList = wfActRuTaskDao.findBySourceId(wfActHiTask.getSourceId());
                    }
                }

                for (WfActRuTask wfActRuTask : ruTaskList) {
                    if (viewHiTask.getAssignee().equals(wfActRuTask.getAssignee())){
                        idMapping.put(oldWfActHiTask.getId(),wfActRuTask.getId());

                        TaskVo taskVo = actTaskService.getTask(wfActRuTask.getId());

                        List<WfActHiComment> commentList = wfActHiCommentService.getCommentList(viewHiTask);
                        if (commentList.size() > 0){
                            Map<String, Object> typeAndUser = this.getAddTypeAndUser(commentList);
                            if (typeAndUser.get("type") != null){
                                String completeType = typeAndUser.get("type").toString();
                                taskVo.setCompleteType(completeType);
                                if ("entrust".equals(completeType)){
                                    taskVo.setEntrustUser(((JSONArray) typeAndUser.get("userId")).get(0).toString());
                                }else {
                                    taskVo.setAddUser((JSONArray) typeAndUser.get("userId"));
                                }
                            }else {
                                taskVo.setCompleteType("task");
                            }
                            taskVo.setJumpEntrust(true);
                            // 设置审批意见字段
                            this.setFormFieldList(taskVo,commentList);
                            String taskId = actTaskService.completeTask(taskVo);
                            wfActHiTaskDao.updateTime(taskId,oldWfActHiTask.getStartTime(),oldWfActHiTask.getApprovalTime());
                            idMapping.put(viewHiTask.getId(),taskId);
                        }



                    }
                }

            }

        }


        return idMapping;
    }

    /**
     * 获取原ID
     * @param idMapping
     * @param oldSourceId
     * @param newActId
     * @return
     */
    public String getSourceId(Map<String,String> idMapping,String oldSourceId,String newActId){
        String newTaskId = idMapping.get(oldSourceId);
        if (StringUtils.isNotBlank(newTaskId)){
            return newTaskId;
        }

        HistoricTaskInstance hiTask = ActTaskUtils.getHiTask(oldSourceId);
        if (hiTask != null){
            Task task = ActTaskUtils.getTask(hiTask.getTaskDefinitionKey(), newActId);
            if (task != null){
                idMapping.put(oldSourceId,task.getId());
                return task.getId();
            }
        }


        return null;
    }

    /**
     * 获取该恩物产生的加签类型
     * @param commentList
     * @return
     */
    public Map<String,Object> getAddTypeAndUser(List<WfActHiComment> commentList){
        Map<String,Object> res = new HashMap<>();

        for (WfActHiComment wfActHiComment : commentList) {
            if (wfActHiComment.getMessage().startsWith("前加签:")) {
                res.put("type","addBefore");
                res.put("userId",this.commentToUserIdList(wfActHiComment.getMessage()));
            } else if (wfActHiComment.getMessage().startsWith("后加签:")) {
                res.put("type","addAfter");
                res.put("userId",this.commentToUserIdList(wfActHiComment.getMessage()));
            }else if (wfActHiComment.getMessage().startsWith("转签:")) {
                res.put("type","entrust");
                res.put("userId",this.commentToUserIdList(wfActHiComment.getMessage()));
            }
        }

        return res;
    }

    /**
     * 将审批意见转换成用户ID
     * @return
     */
    public JSONArray commentToUserIdList(String comment){
        JSONArray res = new JSONArray();
        String[] split = comment.split(":");
        String[] userNameList = split[1].split(",");
        for (String userName : userNameList) {
            SysUser sysUser = sysUserDao.selectUserByNickName(userName);
            res.add(sysUser.getId());
        }

        return res;
    }

    /**
     * 获取用于恢复的历史审批任务
     * @param actId 流程实例ID
     * @return
     */
    public Map<String,List<Object>> getRestoreHiTask(String actId){
        Map<String,List<Object>> hiTaskMap = new HashMap<>();
        List<ViewHiTask> hiTaskList = viewHiTaskDao.findList(new ViewHiTask(actId));

        for (ViewHiTask viewHiTask : hiTaskList) {
            if ("actTask".equals(viewHiTask.getType()) && !"comment".equals(viewHiTask.getSourceType())){
                HistoricTaskInstance hiTask = historyService.createHistoricTaskInstanceQuery().taskId(viewHiTask.getId()).includeTaskLocalVariables().singleResult();

                if (hiTaskMap.get(hiTask.getTaskDefinitionKey()) != null){
                    hiTaskMap.get(hiTask.getTaskDefinitionKey()).add(hiTask);
                }else {
                    List<Object> taskList = new ArrayList<>();
                    taskList.add(hiTask);
                    hiTaskMap.put(hiTask.getTaskDefinitionKey(),taskList);
                }

            }else {
                WfActHiTask wfActHiTask = wfActHiTaskDao.getById(viewHiTask.getId());

                if (hiTaskMap.get(wfActHiTask.getSourceId()) != null){
                    hiTaskMap.get(wfActHiTask.getSourceId()).add(wfActHiTask);
                }else {
                    List<Object> taskList = new ArrayList<>();
                    taskList.add(wfActHiTask);
                    hiTaskMap.put(wfActHiTask.getSourceId(),taskList);
                }
            }
        }

        return hiTaskMap;
    }

    /**
     * 恢复任务
     * @param actId 流程实例ID
     */
    public void restoreTask(String actId,Map<String, List<Object>> restoreHiTaskMap,Map<String,Object> idMapping,List<String> filtrationTask){
        List<ViewRuTask> viewRuTaskList = viewRuTaskDao.findListByActId(actId);

        List<ViewRuTask> ruTaskList = new ArrayList<>();
        for (ViewRuTask viewRuTask : viewRuTaskList) {
            if (!filtrationTask.contains(viewRuTask.getId())){
                ruTaskList.add(viewRuTask);
            }
        }

        if (ruTaskList.size() == 0){
            return;
        }

        // 循环当前最新的待办
        for (ViewRuTask viewRuTask : ruTaskList) {

            if ("actTask".equals(viewRuTask.getType())) {
                // 提交Activity的任务
                restoreActTask(restoreHiTaskMap, filtrationTask, viewRuTask);
            }

        }

        // 继续提交新产生的任务
        this.restoreTask(actId,restoreHiTaskMap,idMapping,filtrationTask);
    }

    /**
     * 提交Activity的任务
     * @param restoreHiTaskMap
     * @param filtrationTask
     * @param viewRuTask
     */
    private void restoreActTask(Map<String, List<Object>> restoreHiTaskMap, List<String> filtrationTask, ViewRuTask viewRuTask) {
        Task task = ActTaskUtils.getTask(viewRuTask.getId());
        if (task != null){
            List<Object> hiTaskList = restoreHiTaskMap.get(task.getTaskDefinitionKey());

            if (hiTaskList != null && hiTaskList.size() > 0){
                HistoricTaskInstance historicTaskInstance = (HistoricTaskInstance) hiTaskList.get(0);

                taskService.setAssignee(task.getId(),historicTaskInstance.getAssignee());
                if (historicTaskInstance.getEndTime() != null){
                    List<Comment> taskCommentList = taskService.getTaskComments(historicTaskInstance.getId());

                    for (Comment hiComment : taskCommentList) {
                        taskService.addComment(viewRuTask.getId(), viewRuTask.getActId(),hiComment.getFullMessage());
                    }
                    taskService.complete(task.getId(),historicTaskInstance.getTaskLocalVariables());
                    actTaskService.updateHiTaskTime(task.getId(),historicTaskInstance.getStartTime(),historicTaskInstance.getEndTime());
                }else {
                    actTaskDao.updateActRuTaskTime(task.getId(), historicTaskInstance.getStartTime());
                    actTaskService.updateHiTaskTime(task.getId(),historicTaskInstance.getStartTime(),historicTaskInstance.getEndTime());
                    filtrationTask.add(viewRuTask.getId());
                }

                hiTaskList.remove(0);
            }
        }
    }


    /**
     * 删除流程
     * @param actId 流程实例ID
     */
    public void delActProcess(String actId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(actId).singleResult();
        if (processInstance != null){
            runtimeService.deleteProcessInstance(actId,"restore");
        }
        historyService.deleteHistoricProcessInstance(actId);
    }
}










